package com.example.zookeeper.register;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * @author jw
 */
@Service
@PropertySource(value = "classpath:zookeeper.properties", encoding = "utf-8")
public class ServiceRegistry {
    private static Logger log = LoggerFactory.getLogger(ServiceRegistry.class);

    private CountDownLatch latch = new CountDownLatch(1);

    @Value("${zk.registry.address}")
    private String registryAddress;

    @Value("${zk.node.path}")
    private String nodePath;

    @Value("${zk.node.childpath}")
    private String nodeChildPath;

    @Value("${zk.timeout}")
    private int timeout;

    @PostConstruct
    public void initServer() {

    }

    public void register(String data) {
        if (data != null) {
            ZooKeeper zk = connectServer();
            if (zk != null) {
                createNode(zk, data);
            }
        }
    }

    /**
     * 连接 zookeeper 服务器
     */
    private ZooKeeper connectServer() {
        ZooKeeper zk = null;
        try {
            zk = new ZooKeeper(registryAddress, timeout, event -> {
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    latch.countDown();
                    log.info("Watcher.........");
                }
            });
            latch.await();
        } catch (IOException | InterruptedException e) {
            log.error("", e);
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        return zk;
    }

    /**
     * 创建节点
     *
     */
    private void createNode(ZooKeeper zk, String data) {
        try {
            //父节点不存在时进行创建
            Stat stat = zk.exists(nodePath, true);
            if (stat == null) {
                zk.create(nodePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            //这里的第一个参数和3.4.13版本的zookeeper不一样，如果不加父目录，直接就是使用/app/会报错，所以智能加父目录
            //CreateMode.EPHEMERAL_SEQUENTIAL,创建临时顺序节点,客户端会话结束后，节点将会被删除
            String createPath = zk.create(nodePath + nodeChildPath, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            log.info("zk节点已创建 ({} =>; {})", data, createPath);
        } catch (KeeperException | InterruptedException e) {
            log.info("", e);
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
    }
}
